// 版权所有 Epic Games, Inc. 保留所有权利。

#include "AbilityTask_WaitForInteractableTargets_SingleLineTrace.h"
#include "Interaction/InteractionStatics.h"
#include "DrawDebugHelpers.h"
#include "Engine/World.h"
#include "TimerManager.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(AbilityTask_WaitForInteractableTargets_SingleLineTrace)

UAbilityTask_WaitForInteractableTargets_SingleLineTrace::UAbilityTask_WaitForInteractableTargets_SingleLineTrace(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

/**
 * 单线追踪等待可交互目标
 * @param OwningAbility 拥有此任务的游戏能力
 * @param InteractionQuery 交互查询
 * @param TraceProfile 追踪配置文件
 * @param StartLocation 起始位置
 * @param InteractionScanRange 交互扫描范围
 * @param InteractionScanRate 交互扫描频率
 * @param bShowDebug 是否显示调试信息
 * @return 创建的 UAbilityTask_WaitForInteractableTargets_SingleLineTrace 对象
 */
UAbilityTask_WaitForInteractableTargets_SingleLineTrace* UAbilityTask_WaitForInteractableTargets_SingleLineTrace::WaitForInteractableTargets_SingleLineTrace(UGameplayAbility* OwningAbility, FInteractionQuery InteractionQuery, FCollisionProfileName TraceProfile, FGameplayAbilityTargetingLocationInfo StartLocation, float InteractionScanRange, float InteractionScanRate, bool bShowDebug)
{
	UAbilityTask_WaitForInteractableTargets_SingleLineTrace* MyObj = NewAbilityTask<UAbilityTask_WaitForInteractableTargets_SingleLineTrace>(OwningAbility); // 创建新的能力任务对象
	MyObj->InteractionScanRange = InteractionScanRange; // 设置交互扫描范围
	MyObj->InteractionScanRate = InteractionScanRate; // 设置交互扫描频率
	MyObj->StartLocation = StartLocation; // 设置起始位置
	MyObj->InteractionQuery = InteractionQuery; // 设置交互查询
	MyObj->TraceProfile = TraceProfile; // 设置追踪配置文件
	MyObj->bShowDebug = bShowDebug; // 设置是否显示调试信息

	return MyObj; // 返回创建的对象
}

/**
 * 激活任务
 */
void UAbilityTask_WaitForInteractableTargets_SingleLineTrace::Activate()
{
	SetWaitingOnAvatar(); // 设置等待角色

	UWorld* World = GetWorld(); // 获取世界
	World->GetTimerManager().SetTimer(TimerHandle, this, &ThisClass::PerformTrace, InteractionScanRate, true); // 设置定时器定期执行追踪
}

/**
 * 任务销毁时调用
 * @param AbilityEnded 能力是否结束
 */
void UAbilityTask_WaitForInteractableTargets_SingleLineTrace::OnDestroy(bool AbilityEnded)
{
	if (UWorld* World = GetWorld()) // 如果世界存在
	{
		World->GetTimerManager().ClearTimer(TimerHandle); // 清除定时器
	}

	Super::OnDestroy(AbilityEnded); // 调用父类销毁方法
}

/**
 * 执行追踪
 */
void UAbilityTask_WaitForInteractableTargets_SingleLineTrace::PerformTrace()
{
	AActor* AvatarActor = Ability->GetCurrentActorInfo()->AvatarActor.Get(); // 获取角色
	if (!AvatarActor) // 如果角色不存在
	{
		return;
	}

	UWorld* World = GetWorld(); // 获取世界

	TArray<AActor*> ActorsToIgnore; // 要忽略的角色数组
	ActorsToIgnore.Add(AvatarActor); // 添加角色到忽略列表

	const bool bTraceComplex = false; // 是否复杂追踪
	FCollisionQueryParams Params(SCENE_QUERY_STAT(UAbilityTask_WaitForInteractableTargets_SingleLineTrace), bTraceComplex); // 碰撞查询参数
	Params.AddIgnoredActors(ActorsToIgnore); // 添加忽略角色

	FVector TraceStart = StartLocation.GetTargetingTransform().GetLocation(); // 追踪起始点
	FVector TraceEnd; // 追踪结束点
	AimWithPlayerController(AvatarActor, Params, TraceStart, InteractionScanRange, OUT TraceEnd); // 使用玩家控制器进行瞄准

	FHitResult OutHitResult; // 命中结果
	LineTrace(OutHitResult, World, TraceStart, TraceEnd, TraceProfile.Name, Params); // 执行射线检测

	TArray<TScriptInterface<IInteractableTarget>> InteractableTargets; // 可交互目标数组
	UInteractionStatics::AppendInteractableTargetsFromHitResult(OutHitResult, InteractableTargets); // 从命中结果中追加可交互目标

	UpdateInteractableOptions(InteractionQuery, InteractableTargets); // 更新可交互选项

#if ENABLE_DRAW_DEBUG
	if (bShowDebug) // 如果显示调试信息
	{
		FColor DebugColor = OutHitResult.bBlockingHit ? FColor::Red : FColor::Green; // 调试颜色
		if (OutHitResult.bBlockingHit) // 如果有阻挡命中
		{
			DrawDebugLine(World, TraceStart, OutHitResult.Location, DebugColor, false, InteractionScanRate); // 绘制调试线
			DrawDebugSphere(World, OutHitResult.Location, 5, 16, DebugColor, false, InteractionScanRate); // 绘制调试球体
		}
		else
		{
			DrawDebugLine(World, TraceStart, TraceEnd, DebugColor, false, InteractionScanRate); // 绘制调试线
		}
	}
#endif // ENABLE_DRAW_DEBUG
}